package util

import (
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"regexp"
	"strconv"
	"strings"
)

/** 基本用法
Router.GET("/validate", func(c *common-admin.Context) {
	var formHelper util.FormHelper
	params := [][]string{
		{"name|姓名", "string", "required"},
		{"age|年龄", "float32", "num|has", "1,150"},
		{"mobile", "string", "mobile|has"},
		{"sex|性别", "string", "whitelist", "male,female"},
		{"nickname|昵称", "string", "hanzi|has", "2,5"},
		{"email", "string", "email|has"},
		{"idcard", "string", "idcard|has"},
		{"link", "string", "url|has"},
		{"regex|身份证正则", "string", "regex|has", `(^([\d]{15}|[\d]{18}|[\d]{17}x)$)`},
		{"password|密码", "string", "mixstring", "3,6"},
		{"repassword|密码", "string", "same", "password"},
		{"searchParams", "string-no-filter"},
	}
	data, err := formHelper.Params(params, c)
	if err != nil {
		c.String(200, "%v", err)
		return
	}
	c.String(200, "%s", data)
})
*/

type FormHelper struct {
	Prefix string
	ErrMsg string
}

type Validator struct {
	FuncName   string //调用函数名
	FuncParams string //调用辅助参数
	ErrName    string //参数中文名称
	Value      string //参数值
}

func (f *FormHelper) Params(params [][]string, c *gin.Context) (data map[string]interface{},
	err error) {
	if len(params) < 1 {
		err = errors.New("参数错误")
		return
	}
	data = make(map[string]interface{}, 10)
	for _, v := range params {
		name := v[0]
		paramType := v[1]
		errName := ""
		if strings.Contains(name, "|") {
			tem := strings.Split(v[0], "|")
			name = tem[0]
			errName = tem[1]
		}
		var value interface{}
		if c.Request.Method == "GET" {
			if paramType == "array" {
				value = c.QueryArray(name)
			} else {
				value = strings.Trim(c.DefaultQuery(name, ""), "")
			}
		} else {
			if paramType == "array" {
				value = c.PostFormArray(name)
			} else {
				value = strings.Trim(c.DefaultPostForm(name, ""), "")
			}
		}
		switch v[1] {
		case "int":
			data[name], _ = strconv.Atoi(value.(string))
		case "int32":
			value, _ := strconv.ParseInt(value.(string), 10, 32)
			data[name] = int32(value)
		case "int64":
			data[name], _ = strconv.ParseInt(value.(string), 10, 64)
		case "float32":
			value, _ := strconv.ParseFloat(value.(string), 32)
			data[name] = float32(value)
		case "float64":
			data[name], _ = strconv.ParseFloat(value.(string), 64)
		case "string":
			data[name] = f.Param_filter(value.(string))
		case "array":
			data[name] = value.([]string)
		case "string-no-filter":
			data[name] = value.(string)
		default:
			data[name] = f.Param_filter(value.(string))
		}
		indexLen := len(v)
		// 数组、例外等类型不参与函数过滤，直接跳入下一个循环
		if indexLen < 3 || v[2] == "array" || v[2] == "except" {
			continue
		}
		has := false //默认关闭字段存在验证
		if strings.Contains(v[2], "|") {
			arr := strings.Split(v[2], "|")
			if arr[1] == "has" {
				has = true //开启存在验证，值为空的时候不验证
			}
			v[2] = arr[0]
		}
		if has && (data[name] == "" || data[name] == 0) { //为空跳过验证
			continue
		}
		funcParams := ""
		if indexLen > 3 {
			funcParams = v[3]
			// 当验证函数为same的时候，参数为same指向的表单数据的值
			if v[2] == "same" {
				funcParams = data[v[3]].(string)
			}
		}
		Validator := &Validator{
			FuncName:   v[2],           //调用函数名
			FuncParams: funcParams,     //调用辅助参数
			ErrName:    errName,        //参数中文名称
			Value:      value.(string), //参数值
		}
		res := f.Validate(Validator)
		if !res { //非法数据，该情况请注意接收返回的错误信息,保存于error中
			//fmt.Printf("err:%s \n",f.ErrMsg)
			err = errors.New(f.ErrMsg)
			return
		}
	}
	//Log(data)
	return
}

func (f *FormHelper) Param_filter(value string) string {
	str := `(?:")|(?:--)|(/\\*(?:.|[\\n\\r])*?\\*/)|(\b(select|update|and|or|delete|insert|trancate|char|chr|into|substr|ascii|declare|exec|count|master|into|drop|execute)\b)`
	re, _ := regexp.Compile(str)
	value = re.ReplaceAllString(value, "")

	str2 := `<(\\/?)(script|i?frame|style|html|body|title|link|meta|object|\\?|\\%)([^>]*?)>`
	re2, _ := regexp.Compile(str2)
	value = re2.ReplaceAllString(value, "")
	return value
}

//通用验证调用
func (f *FormHelper) Validate(Validator *Validator) bool {
	switch Validator.FuncName {
	case "required":
		return f.Required(Validator.Value, Validator.ErrName)
	case "mobile":
		return f.Mobile(Validator.Value, Validator.ErrName)
	case "email":
		return f.Email(Validator.Value, Validator.ErrName)
	case "url":
		return f.Url(Validator.Value, Validator.ErrName)
	case "idcard":
		return f.Idcard(Validator.Value, Validator.ErrName)
	case "ip":
		return f.Ip(Validator.Value, Validator.ErrName)
	case "same":
		return f.Same(Validator.Value, Validator.FuncParams, Validator.ErrName)
	case "regex":
		return f.Regex(Validator.Value, Validator.FuncParams, Validator.ErrName)
	case "numberic":
		return f.Numberic(Validator.Value, Validator.ErrName)
	case "length":
		min, max := f.GetIntFuncParams(Validator.FuncParams)
		return f.Length(Validator.Value, min, max, Validator.ErrName)
	case "num":
		min := 0.00
		max := 999999.00
		if len(Validator.FuncParams) > 0 {
			if strings.Contains(Validator.FuncParams, ",") {
				arr := strings.Split(Validator.FuncParams, ",")
				var err error
				min, err = strconv.ParseFloat(arr[0], 64)
				if err != nil {
					f.ErrMsg = "验证函数参数错误1"
					return false
				}
				max, err = strconv.ParseFloat(arr[1], 64)
				if err != nil {
					f.ErrMsg = "验证函数参数错误2"
					return false
				}
				if min > max {
					min, max = max, min
				}
			} else {
				num, err := strconv.ParseFloat(Validator.FuncParams, 64)
				if err != nil {
					//f.ErrMsg = "验证函数参数错误3"
					f.ErrMsg = err.Error()
					return false
				}
				min, max = num, num
			}
		}
		return f.num(Validator.Value, min, max, Validator.ErrName)
	case "mixstring":
		min, max := f.GetIntFuncParams(Validator.FuncParams)
		return f.Length(Validator.Value, min, max, Validator.ErrName)
	case "hanzi":
		min, max := f.GetIntFuncParams(Validator.FuncParams)
		return f.Hanzi(Validator.Value, min, max, Validator.ErrName)
	case "whitelist":
		if len(Validator.FuncParams) == 0 {
			f.ErrMsg = "验证函数参数错误4"
			return false
		}
		var itemList []string
		if strings.Contains(Validator.FuncParams, ",") {
			itemList = strings.Split(Validator.FuncParams, ",")
		} else {
			itemList = append(itemList, Validator.FuncParams)
		}
		return f.WhiteList(Validator.Value, itemList, Validator.ErrName)
	}
	return false
}

func (f *FormHelper) Required(value, errName string) bool {
	if value == "" {
		if len(errName) < 1 {
			f.ErrMsg = "该项值不能为空"
		} else {
			f.ErrMsg = errName + "不能为空"
		}
		return false
	}
	return true
}

func (f *FormHelper) Mobile(value, errName string) bool {
	reg, _ := regexp.Compile(`^1[3,4,5,6,7,8,9]{1}[\d]{9}`)
	if !reg.MatchString(value) {
		if len(errName) < 1 {
			f.ErrMsg = "请输入正确的手机号"
		} else {
			f.ErrMsg = "请输入正确的" + errName
		}
		return false
	}
	return true
}

func (f *FormHelper) Email(value, errName string) bool {
	reg, _ := regexp.Compile(`[a-z0-9&\-_.]+@[\w\-_]+([\w\-.]+)?\.[\w\-]+`)
	if !reg.MatchString(value) {
		if len(errName) < 1 {
			f.ErrMsg = "请输入正确的邮箱"
		} else {
			f.ErrMsg = "请输入正确的" + errName
		}
		return false
	}
	return true
}

func (f *FormHelper) Url(value, errName string) bool {
	reg, _ := regexp.Compile("^(http|https):\\/\\/[A-Za-z0-9]+\\.[A-Za-z0-9]+[\\/=\\?%\\-&_~`@[\\]\\':+!]*([^<>\"\"])*$")
	if !reg.MatchString(value) {
		if len(errName) < 1 {
			f.ErrMsg = "请输入正确的链接地址"
		} else {
			f.ErrMsg = "请输入正确的" + errName
		}
		return false
	}
	return true
}

func (f *FormHelper) Idcard(value, errName string) bool {
	reg, _ := regexp.Compile(`(^([\d]{15}|[\d]{18}|[\d]{17}x)$)`)
	if !reg.MatchString(value) {
		if len(errName) < 1 {
			f.ErrMsg = "请输入正确的身份证"
		} else {
			f.ErrMsg = "请输入正确的" + errName
		}
		return false
	}
	return true
}

func (f *FormHelper) Ip(value, errName string) bool {
	reg, _ := regexp.Compile(`^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$`)
	if !reg.MatchString(value) {
		if len(errName) < 1 {
			f.ErrMsg = "请输入正确的IP地址"
		} else {
			f.ErrMsg = "请输入正确的" + errName
		}
		return false
	}
	return true
}

func (f *FormHelper) Mixstring(value string, min int, max int, errName string) bool {
	minLen := strconv.Itoa(min)
	maxLen := strconv.Itoa(max)
	reg, _ := regexp.Compile("^[\\d]{" + minLen + "," + maxLen + "}$")
	if !reg.MatchString(value) {
		if len(errName) < 1 {
			f.ErrMsg = "请输入长度在" + minLen + "-" + maxLen + "位的字母/数字组合"
		} else {
			f.ErrMsg = errName + "必须为" + minLen + "-" + maxLen + "位字母/数字组合"
		}
		return false
	}
	return true
}

func (f *FormHelper) Hanzi(value string, min int, max int, errName string) bool {
	minLen := strconv.Itoa(min)
	maxLen := strconv.Itoa(max)
	reg, _ := regexp.Compile("^([\\x{4e00}-\\x{9fa5}]){" + minLen + "," + maxLen + "}$")
	if !reg.MatchString(value) {
		if len(errName) < 1 {
			f.ErrMsg = "请输入" + minLen + "-" + maxLen + "个汉字"
		} else {
			f.ErrMsg = errName + "必须为" + minLen + "-" + maxLen + "个汉字"
		}
		return false
	}
	return true
}

func (f *FormHelper) Regex(value, partten, errName string) bool {
	reg, err := regexp.Compile(partten)
	if err != nil {
		f.ErrMsg = "正则表达式错误"
		return false
	}
	if !reg.MatchString(value) {
		if len(errName) < 1 {
			f.ErrMsg = "请输入正确的值"
		} else {
			f.ErrMsg = "请输入正确的" + errName
		}
		return false
	}
	return true
}

func (f *FormHelper) Length(value string, min int, max int, errName string) bool {
	length := len(value)
	minLen := strconv.Itoa(min)
	maxLen := strconv.Itoa(max)
	if length < min {
		if len(errName) < 1 {
			f.ErrMsg = "该项值不能小于" + minLen + "位"
		} else {
			f.ErrMsg = errName + "不能小于" + minLen + "位"
		}
		return false
	}
	if length > max {
		if len(errName) < 1 {
			f.ErrMsg = "该项值不能大于" + maxLen + "位"
		} else {
			f.ErrMsg = errName + "不能大于" + maxLen + "位"
		}
		return false
	}
	return true
}

func (f *FormHelper) num(value string, min float64, max float64, errName string) bool {
	val, _ := strconv.ParseFloat(value, 64)
	minVal := strconv.FormatFloat(float64(min), 'f', 2, 64)
	maxVal := strconv.FormatFloat(float64(max), 'f', 2, 64)
	if val < min {
		if len(errName) < 1 {
			f.ErrMsg = "该项值不能小于" + minVal
		} else {
			f.ErrMsg = errName + "不能小于" + minVal
		}
		return false
	}
	if val > max {
		if len(errName) < 1 {
			f.ErrMsg = "该项值不能大于" + maxVal
		} else {
			f.ErrMsg = errName + "不能大于" + maxVal
		}
		return false
	}
	return true
}

func (f *FormHelper) Numberic(value string, errName string) bool {
	reg, _ := regexp.Compile("^[1-9][0-9]+$")
	if !reg.MatchString(value) {
		if len(errName) < 1 {
			f.ErrMsg = "请输入正确的数字"
		} else {
			f.ErrMsg = errName + "必须为纯数字"
		}
		return false
	}
	return true
}

func (f *FormHelper) Same(value, same, errName string) bool {
	if value != same {
		if len(errName) < 1 {
			f.ErrMsg = "两次输入的值不一致"
		} else {
			f.ErrMsg = "两次输入的" + errName + "不一致"
		}
		return false
	}
	return true
}

func (f *FormHelper) WhiteList(value string, itemList []string, errName string) bool {
	flag := false
	for _, item := range itemList {
		if item == value {
			flag = true
		}
	}
	if !flag {
		if len(errName) < 1 {
			f.ErrMsg = "该项值不在列表中"
		} else {
			f.ErrMsg = fmt.Sprintf("该", errName, "不在列表中")
		}
		return false
	}
	return true
}

func (f *FormHelper) GetIntFuncParams(funcParams string) (min, max int) {
	min = 1
	max = 15
	if len(funcParams) > 0 {
		if strings.Contains(funcParams, ",") {
			arr := strings.Split(funcParams, ",")
			var err error
			min, err = strconv.Atoi(arr[0])
			if err != nil {
				f.ErrMsg = "验证函数参数错误"
				return
			}
			max, err = strconv.Atoi(arr[1])
			if err != nil {
				f.ErrMsg = "验证函数参数错误"
				return
			}
			if min > max {
				min, max = max, min
			}
		} else {
			num, err := strconv.Atoi(funcParams)
			if err != nil {
				f.ErrMsg = "验证函数参数错误"
				return
			}
			min, max = num, num
		}
	}
	return
}
